#ifndef __frustum_h__
#define __frustum_h__

/**
	Frustum
*/

#include "math.h"

namespace kraw
{
    class Plane
    {
    public:
        Plane()
        {
        }
        Plane(float a, float b, float c, float d)
        {
            set(a,b,c,d);
        }
        void set(float a, float b, float c, float d)
        {
            normal = vec3f(a,b,c);
            float len = normal.length();
            normal /= len;
            dist = d/len;
        }
        float dot(const vec3f& v) const
        {
            return normal.x*v.x + normal.y*v.y + normal.z*v.z + dist;
        }
        
        vec3f normal;
        float dist;
    };
    
    class Frustum
    {
    public:
        enum {
            kNear = 0,
            kFar,
            kBottom,
            kTop,
            kLeft,
            kRight,
            kNumPlanes
        };
        
        Plane planes[kNumPlanes];
        
        void set(const mat4f& mat)
        {
            planes[kNear].set(mat.at(2,0) + mat.at(3,0),
                              mat.at(2,1) + mat.at(3,1),
                              mat.at(2,2) + mat.at(3,2),
                              mat.at(2,3) + mat.at(3,3));
            planes[kFar].set(-mat.at(2,0) + mat.at(3,0),
                             -mat.at(2,1) + mat.at(3,1),
                             -mat.at(2,2) + mat.at(3,2),
                             -mat.at(2,3) + mat.at(3,3));
            planes[kBottom].set(mat.at(1,0) + mat.at(3,0),
                                mat.at(1,1) + mat.at(3,1),
                                mat.at(1,2) + mat.at(3,2),
                                mat.at(1,3) + mat.at(3,3));
            planes[kTop].set(-mat.at(1,0) + mat.at(3,0),
                             -mat.at(1,1) + mat.at(3,1),
                             -mat.at(1,2) + mat.at(3,2),
                             -mat.at(1,3) + mat.at(3,3));
            planes[kLeft].set(mat.at(0,0) + mat.at(3,0),
                              mat.at(0,1) + mat.at(3,1),
                              mat.at(0,2) + mat.at(3,2),
                              mat.at(0,3) + mat.at(3,3));
            planes[kRight].set(-mat.at(0,0) + mat.at(3,0),
                               -mat.at(0,1) + mat.at(3,1),
                               -mat.at(0,2) + mat.at(3,2),
                               -mat.at(0,3) + mat.at(3,3));
        }
        
        bool testSphere(const vec3f& pos, float radius) const
        {
            for (int i=0; i<kNumPlanes; i++) {
                if (planes[i].dot(pos) < -radius)
                    return false;
            }
            return true;
        }
        
        //bool testBox() ...
    };
}

#endif
